home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr05 / xnot12a.zip / EXTEND.C < prev    next >
C/C++ Source or Header  |  1993-06-16  |  23KB  |  958 lines

  1. #include "jam.h"
  2. /*
  3.  *    Extended (M-X) commands, rebinding, and 
  4.  *    startup file processing.
  5.  */
  6. #include "stdlib.h"
  7. #include    "def.h"
  8. #include    "kbd.h"
  9. #include    "macro.h"
  10. #include    "keyname.h"
  11. #include     "stdio.h"
  12.  
  13. #ifndef WINDOWED
  14. # include "string.h"
  15. #endif
  16.  
  17. #include    "key.h"
  18. # ifndef    BINDKEY
  19. #  define    BINDKEY        /* bindkey is used by FKEYS startup code */
  20. # endif
  21.  
  22. #define FreeLine(lp)\
  23. { lkill(lp);\
  24.   lp = (LINE *)0;\
  25. }
  26.  
  27. static char *nomatch = "[No Match!]";
  28. static char *outamemory = "Out of memory";   /* JAM */
  29.  
  30. static KEYMAP *rn_(realocmap,(KEYMAP *curmap));
  31. static VOID rn_(fixmap,(KEYMAP *curmap, KEYMAP *mp, KEYMAP *mt));
  32. static int rn_(remap, (KEYMAP *curmap, int c, PF funct, KEYMAP *pref_map));
  33. static int rn_(dobind,(KEYMAP *curmap, char *p, int unbind));
  34. static char *rn_(skipwhite, (char *s));
  35. static char *rn_(parsetoken, (char *s));
  36. static int rn_(do_extend, (char *xname, int f, int n));
  37.  
  38. /* insert a string, mainly for use from macros 
  39. * (created by selfinsert) 
  40. */
  41. /*ARGSUSED*/
  42. insert(f, n)
  43. int f, n;
  44. {
  45.     register char *cp;
  46.     char buf[128];
  47.     register int count;
  48.     int c;
  49.  
  50.   if (curbp->b_flag & BFVIEW)
  51.     {
  52.       ttbeep();
  53.       return FALSE;
  54.     }
  55.  
  56.   if (filetimechanged(curbp))
  57.     return(FALSE);
  58.   clearUndo(curbp);
  59.  
  60.  
  61.     if(inmacro) {
  62.     while(--n >= 0) {
  63.         for(count = 0; count < maclcur->l_used; count++) {
  64.         if((((c=maclcur->l_text[count]) == '\n') ? lnewline()
  65.             : linsert(1, c)) != TRUE) return FALSE;
  66.         }
  67.     }
  68.     maclcur = maclcur->l_fp;
  69.     return TRUE;
  70.     }
  71.     if(n==1) 
  72.       thisflag |= CFINS; /* CFINS means selfinsert can tack on end */
  73.  
  74.     if(eread("Insert: ", buf, sizeof(buf), EFNEW) == FALSE) 
  75.       return FALSE;
  76.     while(--n >= 0) {
  77.     cp = buf;
  78.     while(*cp) {
  79.         if(((*cp == '\n') ? lnewline() : linsert(1, *cp)) != TRUE)
  80.         return FALSE;
  81.         cp++;
  82.     }
  83.     }
  84.     return TRUE;
  85. }
  86.  
  87. /*
  88.  * Bind a key to a function.  Cases range from the trivial (replacing an
  89.  * existing binding) to the extremly complex (creating a new prefix in a
  90.  * map_element that already has one, so the map_element must be split,
  91.  * but the keymap doesn't have enough room for another map_element, so
  92.  * the keymap is reallocated).    NO ATTEMPT IS MADE TO RECLAIM SPACE NO
  93.  * LONGER USED, if this is a problem flags must be added to indicate
  94.  * malloced verses static storage in both keymaps and map_elements.
  95.  * Structure assignments would come in real handy, but K&R based compilers
  96.  * don't have them.  Care is taken so running out of memory will leave
  97.  * the keymap in a usable state.
  98.  */
  99. static int remap(curmap, c, funct, pref_map)
  100. register KEYMAP    *curmap;/* pointer to the map being changed */
  101. int    c;        /* character being changed */
  102. PF    funct;        /* function being changed to */
  103. KEYMAP    *pref_map;    /* if funct==prefix, map to bind to or NULL for new */
  104. {
  105.     register int i;
  106.     int    n1, n2, nold;
  107.     KEYMAP    *mp;
  108.     PF    *pfp;
  109.     MAP_ELEMENT *mep;
  110.  
  111.     if(ele >= &curmap->map_element[curmap->map_num] || c < ele->k_base) {
  112.         if(ele > &curmap->map_element[0] && (funct!=prefix ||
  113.             (ele-1)->k_prefmap==NULL)) {
  114.         n1 = c - (ele-1)->k_num;
  115.         } else n1 = HUGEN;
  116.         if(ele < &curmap->map_element[curmap->map_num] && (funct!=prefix ||
  117.             ele->k_prefmap==NULL)) {
  118.         n2 = ele->k_base - c;
  119.         } else n2 = HUGEN;
  120.         if(n1 <= MAPELEDEF && n1 <= n2) {
  121.         ele--;
  122.         if((pfp = (PF *)malloc((unsigned)(c - ele->k_base+1) 
  123.             * sizeof(PF))) == NULL) {
  124.             ewprintf(outamemory);
  125.             return FALSE;
  126.         }
  127.         nold = ele->k_num - ele->k_base + 1;
  128.         for(i=0; i < nold; i++)
  129.             pfp[i] = ele->k_funcp[i];
  130.         while(--n1) pfp[i++] = curmap->map_default;
  131.         pfp[i] = funct;
  132.         ele->k_num = c;
  133.         ele->k_funcp = pfp;
  134.         } else if(n2 <= MAPELEDEF) {
  135.         if((pfp = (PF *)malloc((unsigned)(ele->k_num - c + 1) 
  136.             * sizeof(PF))) == NULL) {
  137.             ewprintf(outamemory);
  138.             return FALSE;
  139.         }
  140.         nold = ele->k_num - ele->k_base + 1;
  141.         for(i=0; i < nold; i++)
  142.             pfp[i+n2] = ele->k_funcp[i];
  143.         while(--n2) pfp[n2] = curmap->map_default;
  144.         pfp[0] = funct;
  145.         ele->k_base = c;
  146.         ele->k_funcp = pfp;
  147.         } else {
  148.         if(curmap->map_num >= curmap->map_max &&
  149.             (curmap = realocmap(curmap)) == NULL) return FALSE;
  150.         if((pfp = (PF *)malloc(sizeof(PF))) == NULL) {
  151.             ewprintf(outamemory);
  152.             return FALSE;
  153.         }
  154.         pfp[0] = funct;
  155.         for(mep = &curmap->map_element[curmap->map_num]; mep > ele; mep--) {
  156.             mep->k_base    = (mep-1)->k_base;
  157.             mep->k_num     = (mep-1)->k_num;
  158.             mep->k_funcp   = (mep-1)->k_funcp;
  159.             mep->k_prefmap = (mep-1)->k_prefmap;
  160.         }
  161.         ele->k_base = c;
  162.         ele->k_num = c;
  163.         ele->k_funcp = pfp;
  164.         ele->k_prefmap = NULL;
  165.         curmap->map_num++;
  166.         }
  167.         if(funct == prefix) {
  168.         if(pref_map != NULL) {
  169.             ele->k_prefmap = pref_map;
  170.         } else {
  171.             if((mp = (KEYMAP *)malloc(sizeof(KEYMAP) +
  172.                 (MAPINIT-1)*sizeof(MAP_ELEMENT))) == NULL) {
  173.                 ewprintf(outamemory);
  174.             ele->k_funcp[c - ele->k_base] = curmap->map_default;
  175.             return FALSE;
  176.             }
  177.             mp->map_num = 0;
  178.             mp->map_max = MAPINIT;
  179.             mp->map_default = rescan;
  180.             ele->k_prefmap = mp;
  181.         }
  182.         }
  183.     } else {
  184.         n1 = c - ele->k_base;
  185.         if(ele->k_funcp[n1] == funct && (funct!=prefix || pref_map==NULL ||
  186.             pref_map==ele->k_prefmap))
  187.         return TRUE;    /* no change */
  188.         if(funct!=prefix || ele->k_prefmap==NULL) {
  189.         if(ele->k_funcp[n1] == prefix)
  190.             ele->k_prefmap = (KEYMAP *)NULL;
  191.         ele->k_funcp[n1] = funct;    /* easy case */
  192.         if(funct==prefix) {
  193.             if(pref_map!=NULL)
  194.             ele->k_prefmap = pref_map;
  195.             else {
  196.             if((mp = (KEYMAP *)malloc(sizeof(KEYMAP) +
  197.                 (MAPINIT-1)*sizeof(MAP_ELEMENT))) == NULL) {
  198.                     ewprintf(outamemory);
  199.                 ele->k_funcp[c - ele->k_base] = curmap->map_default;
  200.                 return FALSE;
  201.             }
  202.             mp->map_num = 0;
  203.             mp->map_max = MAPINIT;
  204.             mp->map_default = rescan;
  205.             ele->k_prefmap = mp;
  206.             }
  207.         }
  208.         } else {
  209.         /* this case is the splits */
  210.         /* determine which side of the break c goes on */
  211.         /* 0 = after break; 1 = before break */
  212.         n2 = 1;
  213.         for(i=0; n2 && i < n1; i++)
  214.             n2 &= ele->k_funcp[i] != prefix;
  215.         if(curmap->map_num >= curmap->map_max &&
  216.             (curmap = realocmap(curmap)) == NULL) return FALSE;
  217.         if((pfp = (PF *)malloc((unsigned)(ele->k_num - c + !n2) 
  218.             * sizeof(PF))) == NULL) {
  219.                 ewprintf(outamemory);
  220.             return FALSE;
  221.         }
  222.         ele->k_funcp[n1] = prefix;
  223.         for(i=n1+n2; i <= ele->k_num - ele->k_base; i++)
  224.             pfp[i-n1-n2] = ele->k_funcp[i];
  225.         for(mep = &curmap->map_element[curmap->map_num]; mep > ele; mep--) {
  226.             mep->k_base    = (mep-1)->k_base;
  227.             mep->k_num     = (mep-1)->k_num;
  228.             mep->k_funcp   = (mep-1)->k_funcp;
  229.             mep->k_prefmap = (mep-1)->k_prefmap;
  230.         }
  231.         ele->k_num = c - !n2;
  232.         (ele+1)->k_base = c + n2;
  233.         (ele+1)->k_funcp = pfp;
  234.         ele += !n2;
  235.         ele->k_prefmap = NULL;
  236.         curmap->map_num++;
  237.         if(pref_map == NULL) {
  238.             if((mp = (KEYMAP *)malloc(sizeof(KEYMAP) +
  239.                 (MAPINIT-1)*sizeof(MAP_ELEMENT))) == NULL) {
  240.                     ewprintf(outamemory);
  241.             ele->k_funcp[c - ele->k_base] = curmap->map_default;
  242.             return FALSE;
  243.             }
  244.             mp->map_num = 0;
  245.             mp->map_max = MAPINIT;
  246.             mp->map_default = rescan;
  247.             ele->k_prefmap = mp;
  248.         } else ele->k_prefmap = pref_map;
  249.         }
  250.     }
  251.     return TRUE;
  252. }
  253.  
  254. /* reallocate a keymap, used above 
  255. */
  256. static KEYMAP *realocmap(curmap)
  257. register KEYMAP *curmap;
  258. {
  259.     register KEYMAP *mp;
  260.     register int i;
  261.     extern int nmaps;
  262.  
  263.     if((mp = (KEYMAP *)malloc((unsigned)(sizeof(KEYMAP)+
  264.         (curmap->map_max+(MAPGROW-1))*sizeof(MAP_ELEMENT)))) == NULL) {
  265.         ewprintf(outamemory);
  266.     return NULL;
  267.     }
  268.     mp->map_num = curmap->map_num;
  269.     mp->map_max = curmap->map_max + MAPGROW;
  270.     mp->map_default = curmap->map_default;
  271.     for(i=curmap->map_num; i--; ) {
  272.     mp->map_element[i].k_base    = curmap->map_element[i].k_base;
  273.     mp->map_element[i].k_num    = curmap->map_element[i].k_num;
  274.     mp->map_element[i].k_funcp    = curmap->map_element[i].k_funcp;
  275.     mp->map_element[i].k_prefmap    = curmap->map_element[i].k_prefmap;
  276.     }
  277.     for(i=nmaps; i--; ) {
  278.     if(map_table[i].p_map == curmap) map_table[i].p_map = mp;
  279.     else fixmap(curmap, mp, map_table[i].p_map);
  280.     }
  281.     ele = &mp->map_element[ele - &curmap->map_element[0]];
  282.     return mp;
  283. }
  284.  
  285. /* fix references to a reallocated keymap (recursive) 
  286. */
  287. static VOID fixmap(curmap, mp, mt)
  288. register KEYMAP *mt;
  289. register KEYMAP *curmap;
  290. KEYMAP *mp;
  291. {
  292.     register int i;
  293.  
  294.     for(i = mt->map_num; i--; ) {
  295.     if(mt->map_element[i].k_prefmap != NULL) {
  296.         if(mt->map_element[i].k_prefmap == curmap)
  297.             mt->map_element[i].k_prefmap = mp;
  298.         else fixmap(curmap, mp, mt->map_element[i].k_prefmap);
  299.     }
  300.     }
  301. }
  302.  
  303. /*
  304.  * do the input for local-set-key, global-set-key  and define-key
  305.  * then call remap to do the work.
  306.  */
  307.  
  308. static int dobind(curmap, p, unbind)
  309. register KEYMAP *curmap;
  310. char *p;
  311. int unbind;
  312. {
  313.     PF    funct;
  314.     char    prompt[80];
  315.     char    *pep;
  316.     int    c;
  317.     int    s;
  318.     KEYMAP    *pref_map = NULL;
  319.  
  320.     if(macrodef) {
  321.     /* Keystrokes arn't collected.    Not hard, but pretty useless.
  322.      * Would not work for function keys in any case 
  323.          */
  324.         ewprintf("Can't rebind key in macro");
  325.         return FALSE;
  326.     }
  327.  
  328.     if(inmacro) {
  329.         for(s=0; s < maclcur->l_used - 1; s++) {
  330.         if(doscan(curmap, c=CHARMASK(maclcur->l_text[s])) != prefix) {
  331.             if(remap(curmap, c, prefix, (KEYMAP *)NULL) != TRUE) {
  332.             return FALSE;
  333.             }
  334.         }
  335.         curmap = ele->k_prefmap;
  336.         }
  337.         (VOID) doscan(curmap, c=maclcur->l_text[s]);
  338.         maclcur = maclcur->l_fp;
  339.     } 
  340.         else {
  341.         (VOID) strcpy(prompt, p);
  342.         pep = prompt + strlen(prompt);
  343.         for(;;) {
  344.                 eprompting = TRUE;
  345.         ewprintf("%s", prompt);
  346.         pep[-1] = ' ';
  347.         pep = mykeyname(pep, c = getkey(FALSE));
  348.                 eprompting = FALSE;
  349.         if(doscan(curmap,c) != prefix) 
  350.                   break;
  351.         *pep++ = '-';
  352.         *pep = '\0';
  353.         curmap = ele->k_prefmap;
  354.         }
  355.     }
  356.  
  357.     if(unbind) 
  358.           funct = rescan;
  359.     else {
  360.         if ((s=eread("%s to command: ", prompt, 80, EFFUNC|EFNEW, prompt))
  361.             != TRUE) return s;
  362.         if (((funct = name_function(prompt)) == prefix) ?
  363.                 (pref_map = name_map(prompt)) == NULL : funct==NULL) {
  364.         ewprintf(nomatch);
  365.         return FALSE;
  366.         }
  367.     }
  368.     return remap(curmap, c, funct, pref_map);
  369. }
  370.  
  371. /*
  372.  * bindkey: bind key sequence to a function in
  373.  * the specified map.  Used by excline so it can bind function keys.
  374.  * To close to release to change calling sequence, should just pass
  375.  * KEYMAP *curmap rather than KEYMAP **mapp.
  376. */
  377. bindkey(mapp, fname, keys, kcount)
  378. KEYMAP **mapp;
  379. char *fname;
  380. KCHAR *keys;
  381. int kcount;
  382. {
  383.     KEYMAP    *curmap = *mapp;
  384.     PF    funct;
  385.     int    c;
  386.     KEYMAP    *pref_map = NULL;
  387.  
  388.     if(fname == NULL) funct = rescan;
  389.     else if (((funct = name_function(fname)) == prefix) ?
  390.         (pref_map = name_map(fname)) == NULL : funct==NULL) {
  391.         ewprintf("[No matching function: %s]", fname);
  392.         return FALSE;
  393.     }
  394.     while(--kcount) {
  395.         if(doscan(curmap, c = *keys++) != prefix) {
  396.         if(remap(curmap, c, prefix, (KEYMAP *)NULL) != TRUE)
  397.             return FALSE;
  398.         }
  399.         curmap = ele->k_prefmap;
  400.     }
  401.     (VOID) doscan(curmap, c = *keys);
  402.     return remap(curmap, c, funct, pref_map);
  403. }
  404.  
  405. /*
  406.  * This function modifies the fundamental keyboard map.
  407.  */
  408. /*ARGSUSED*/
  409. bindtokey(f, n)
  410. int f, n;
  411. {
  412.     return dobind(map_table[0].p_map, "Global set key: ", FALSE);
  413. }
  414.  
  415. /*
  416.  * This function modifies the current mode's keyboard map.
  417.  */
  418. /*ARGSUSED*/
  419. localbind(f, n)
  420. int f, n;
  421. {
  422.   return dobind(curbp->b_modes[curbp->b_nmodes]->p_map, 
  423.                 "Local set key: ", FALSE);
  424. }
  425.  
  426. /*
  427.  * This function redefines a key in any keymap.
  428.  */
  429. /*ARGSUSED*/
  430. define_key(f, n)
  431. int f, n;
  432. {
  433. #define BSIZE 48
  434.     static char buf[BSIZE] = "Define key map: ";
  435.     MAPS *mp;
  436.     static int i = -1;
  437.  
  438.     if (i < 0)
  439.       i = strlen(buf);
  440.  
  441.     buf[i] = '\0';
  442.     if(eread(buf, &buf[i], BSIZE - i, EFNEW) != TRUE) 
  443.       return FALSE;
  444.     if((mp = name_mode(&buf[i])) == NULL) {
  445.     ewprintf("Unknown map %s", &buf[i]);
  446.     return FALSE;
  447.     }
  448.     (VOID) strncat(&buf[i], " key: ", BSIZE-i-1);
  449.     return dobind(mp->p_map, buf, FALSE);
  450. }
  451.  
  452. unbindtokey(f, n)
  453. int f, n;
  454. {
  455.     return dobind(map_table[0].p_map, "Global unset key: ", TRUE);
  456. }
  457.  
  458. localunbind(f, n)
  459. int f, n;
  460. {
  461.     return dobind(curbp->b_modes[curbp->b_nmodes]->p_map, "Local unset key: ",
  462.     TRUE);
  463. }
  464.  
  465. /*
  466.  * Extended command. Call the message line
  467.  * routine to read in the command name and apply autocompletion
  468.  * to it. When it comes back, look the name up in the symbol table
  469.  * and run the command if it is found.
  470.  * Print an error if there is anything wrong.
  471.  */
  472. extend(f, n)
  473. int f, n;
  474. {
  475.     int    s;
  476.     char    xname[NXNAME];
  477.  
  478.     if(!(f & FFARG)) 
  479.       s = eread("M-x ", xname, NXNAME, EFNEW|EFFUNC);
  480.     else    
  481.       s = eread("%d M-x ", xname, NXNAME, EFNEW|EFFUNC, n);
  482.     if(s != TRUE) 
  483.       return s;
  484.     return(do_extend(xname, f, n));
  485. }
  486.  
  487. /* Means to do meta-x like stuff which won't echo
  488. * the command into the message line; usually triggered
  489. * by previous call to ExtendedFunction which loads the
  490. * input stream. NOTE special code to prevent hosing up
  491. * macros with function input chars.
  492. */
  493. silent_extend(f, n)
  494. int f, n;
  495. {
  496.     int    i, c;
  497.     char    xname[NXNAME];
  498.  
  499.     for (i = 0; (i < NXNAME) && (c = getkey(FALSE)); )
  500.       if (c != (char)' ')
  501.         xname[i++] = (char)c;
  502.       else
  503.         break;
  504.     if (i <= 0)
  505.       return(TRUE);  /* nothing?, ok */
  506.     xname[i] =0;
  507.  
  508.     /* Running/definit a macro? Revert to real meta-x behavior
  509.     */
  510.     if(macrodef) 
  511.       {
  512.         AddKchar('X' | METABIT);
  513.         AddString(xname);
  514.         AddKchar(CCHR('M'));
  515.         return(TRUE);  
  516.       }
  517.     else
  518.       return(do_extend(xname, 0, 1));
  519. }
  520.  
  521. static int do_extend(xname, f, n)
  522. char *xname;
  523. int f, n;
  524. {
  525.     PF    funct;
  526.  
  527.     if((funct = name_function(xname)) != NULL) {
  528.       if(macrodef) 
  529.             {
  530.               LINE *lp = maclcur;
  531.  
  532.               macro[macrocount-1].m_funct = funct;
  533.               maclcur = lp->l_bp;
  534.               maclcur->l_fp = lp->l_fp;
  535.               free((char *)lp);
  536.         }
  537.       return (*funct)(f, n);
  538.     }
  539.     ewprintf(nomatch);
  540.     return FALSE;
  541. }
  542.  
  543. /*
  544.  * Define the commands needed to do startup-file processing.
  545.  * This code is mostly a kludge just so we can get startup-file processing.
  546.  *
  547.  * If you're serious about having this code, you should rewrite it.
  548.  * To wit:
  549.  *    It has lots of funny things in it to make the startup-file look
  550.  *    like a GNU startup file; mostly dealing with parens and semicolons.
  551.  *    This should all vanish.
  552.  *
  553.  * We define eval-expression because it's easy.     It can make
  554.  * *-set-key or define-key set an arbitrary key sequence, so it isn't
  555.  * useless.
  556.  */
  557.  
  558. /*
  559.  * evalexpr - get one line from the user, and run it.
  560.  */
  561. /*ARGSUSED*/
  562. #define EVALBUF 256
  563. evalexpr(f, n)
  564. int f, n;
  565. {
  566.     int    s;
  567.     char    exbuf[EVALBUF];
  568.  
  569.     if ((s = ereply("Eval: ", exbuf, EVALBUF)) != TRUE)
  570.         return s;
  571.     return excline(exbuf);
  572. }
  573. /*
  574.  * evalbuffer - evaluate the current buffer as line commands. Useful
  575.  *    for testing startup files.
  576.  */
  577. /*ARGSUSED*/
  578. evalbuffer(f, n)
  579. int f, n;
  580. {
  581.     register LINE    *lp;
  582.     register BUFFER *bp = curbp;
  583.     register int    s;
  584.     static char    excbuf[EVALBUF];
  585.  
  586.     for (lp = lforw(bp->b_linep); lp != bp->b_linep; lp = lforw(lp)) {
  587.         if (llength(lp) >= EVALBUF) 
  588.                   return FALSE;
  589.         (VOID) strncpy(excbuf, ltext(lp), llength(lp));
  590.         excbuf[llength(lp)] = '\0';    /* make sure it's terminated */
  591.         if ((s = excline(excbuf)) != TRUE) 
  592.                   return s;
  593.     }
  594.     return TRUE;
  595. }
  596. /*
  597.  * evalfile - go get a file and evaluate it as line commands. You can
  598.  *    go get your own startup file if need be.
  599.  */
  600. /*ARGSUSED*/
  601. evalfile(f, n)
  602. int f, n;
  603. {
  604.     register int    s;
  605.     char        fname[NFILEN];
  606.  
  607.         epreload(dirpath());
  608.     if ((s = ereply("Load file: ", fname, NFILEN)) != TRUE)
  609.       return s;
  610.     return load(fname);
  611. }
  612.  
  613. /*
  614.  * load - go load the file name we got passed.
  615.  */
  616. load(fname) 
  617. char *fname; 
  618. {
  619.     int    s = TRUE;
  620.     int    nbytes;
  621.     char    excbuf[EVALBUF], tmpbuf[NLINE + 1];
  622.  
  623.     if ((fname = adjustname(fname)) == NULL)
  624.       return FALSE;    /* just to be careful */
  625.  
  626.     if (ffropen(fname) != FIOSUC) 
  627.           return FALSE;
  628.         ewprintf("Load file %s... executing", fname);
  629.     while ((s = ffgetline(excbuf, sizeof(excbuf)-1, &nbytes)) == FIOSUC) {
  630.         excbuf[nbytes] = '\0';
  631.         if (excline(excbuf) != TRUE) 
  632.                   {
  633.             s = FIOERR;
  634.                     ttbeep();
  635.                 sprintf(tmpbuf, "Error exec'ing [%s]. Continue",
  636.                             excbuf);
  637.                 if (eyorn(tmpbuf) != TRUE)
  638.                   break;
  639.         }
  640.     }
  641.     (VOID) ffclose();
  642.     excbuf[nbytes] = '\0';
  643.         ewprintf("Done.");
  644.     if(s!=FIOEOF || (nbytes && excline(excbuf)!=TRUE))
  645.         return FALSE;
  646.     return TRUE;
  647. }
  648.  
  649. /*
  650.  * excline - run a line from a load file or eval-expression.
  651.  * if FKEYS is defined, duplicate functionallity of dobind so function
  652.  * key values don't have to fit in type char.
  653.  */
  654. excline(line)
  655. register char *line;
  656. {
  657.     register char    *funcp, *argp = NULL;
  658.     register int    c;
  659.     int    status;
  660.     int    f, n;
  661.     LINE    *lp, *np;
  662.     PF    fp;
  663.     int    bind;
  664.     KEYMAP    *curmap;
  665.     MAPS    *mp;
  666. #define BINDARG  0    /* this arg is key to bind (local/global set key) */
  667. #define BINDNO      1    /* not binding or non-quoted BINDARG */
  668. #define BINDNEXT 2    /* next arg " (define-key) */
  669. #define BINDDO      3    /* already found key to bind */
  670. #define BINDEXT  1    /* space for trailing \0 */
  671.  
  672.     if(macrodef || inmacro) {
  673.         ewprintf(notinmacro);
  674.         return FALSE;
  675.     }
  676.  
  677.     f = 0;
  678.     n = 1;
  679.     funcp = skipwhite(line);
  680.     if (*funcp == '\0') 
  681.           return TRUE;    /* No error on blank lines */
  682.     line = parsetoken(funcp);
  683.     if (*line != '\0') {
  684.         *line++ = '\0';
  685.         line = skipwhite(line);
  686.         if ((*line >= '0' && *line <= '9') || *line == '-') {
  687.             argp = line;
  688.             line = parsetoken(line);
  689.         }
  690.     }
  691.  
  692.     if (argp != NULL) {
  693.         f = FFARG;
  694.         n = atoi(argp);
  695.     }
  696.     if((fp = name_function(funcp)) == NULL) {
  697.         ewprintf("Unknown function: %s", funcp);
  698.         return FALSE;
  699.     }
  700.  
  701.     if(fp == bindtokey || fp == unbindtokey) {
  702.         bind = BINDARG;
  703.         curmap = map_table[0].p_map;
  704.     } else if(fp == localbind || fp == localunbind) {
  705.         bind = BINDARG;
  706.         curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
  707.     } 
  708.         else if (fp == define_key) 
  709.           bind = BINDNEXT;
  710.     else 
  711.           bind = BINDNO;
  712.  
  713.     /* Pack away all the args now...    
  714.         */
  715.     if((np = lalloc(0))==FALSE) 
  716.           return FALSE;
  717.  
  718.         /* alloc head of list
  719.         */
  720.     np->l_fp = np->l_bp = maclcur = np;
  721.         lp = (LINE *)0;
  722.  
  723.         /* parse the stupid line
  724.         */
  725.     while (*line != '\0') {
  726.         argp = skipwhite(line);
  727.         if (*argp == '\0') 
  728.                   break;
  729.         line = parsetoken(argp);
  730.         if (*argp != '"') 
  731.                   {
  732.             if (*argp == '\'') 
  733.                       ++argp;
  734.             if((lp = lalloc((int)(line-argp)+BINDEXT))==NULL) {
  735.             status = FALSE;
  736.             goto cleanup;
  737.             }
  738.             bcopy(argp, ltext(lp), (size_t)(line-argp));
  739.             lp->l_used--;    /* don't count BINDEXT! */
  740.             if(bind == BINDARG) 
  741.                       bind = BINDNO;
  742.           } 
  743.                 else 
  744.                   {    /* Quoted strings special */
  745.             ++argp;
  746.             if(bind != BINDARG) 
  747.                       {
  748.             if((lp = lalloc((int)(line-argp)+BINDEXT))==NULL) 
  749.                           {
  750.                 status = FALSE;
  751.                 goto cleanup;
  752.                   }
  753.                     lp->l_used = 0;
  754.               } 
  755.                     else 
  756.                       {
  757.             key.k_count = 0;
  758.                       }
  759.             
  760.             while (*argp != '"' && *argp != '\0') {
  761.             if (*argp != '\\') c = *argp++;
  762.             else {
  763.                 switch(*++argp) {
  764.                 case 't': case 'T':
  765.                     c = CCHR('I');
  766.                     break;
  767.                 case 'n': case 'N':
  768.                     c = CCHR('J');
  769.                     break;
  770.                 case 'r': case 'R':
  771.                     c = CCHR('M');
  772.                     break;
  773.                 case 'e': case 'E':
  774.                     c = CCHR('[');
  775.                     break;
  776.                 case '^':
  777. /* split into two statements due to bug in OSK cpp 
  778. */
  779.                     c = CHARMASK(*++argp);
  780.                     c = ISLOWER(c) ?
  781.                     CCHR(TOUPPER(c)) : CCHR(c);
  782.                     break;
  783.                 case '0': case '1': case '2': case '3':
  784.                 case '4': case '5': case '6': case '7':
  785.                     c = *argp - '0';
  786.                     if(argp[1] <= '7' && argp[1] >= '0') {
  787.                         c <<= 3;
  788.                     c += *++argp - '0';
  789.                     if(argp[1] <= '7' && argp[1] >= '0') {
  790.                         c <<= 3;
  791.                         c += *++argp - '0';
  792.                     }
  793.                     }
  794.                     break;
  795.                 case 'f': case 'F':
  796.                 case 'k': case 'K':
  797.                     {
  798.                                       /* major ughly patch.. JAM
  799.                                       */
  800.                       char buf[200];
  801.                       int i = 0;
  802.  
  803.                       while (*argp && (*argp != '"'))
  804.                         buf[i++] = *argp++;
  805.                       buf[i] = '\0';
  806.                       argp--;
  807.                       c = findkeyfromstring(buf);
  808.                     }
  809.                     break;
  810.                 default:
  811.                     c = CHARMASK(*argp);
  812.                     break;
  813.                 }
  814.                 argp++;
  815.             }
  816.             if(bind == BINDARG)
  817.                 key.k_chars[key.k_count++] = c;
  818.             else
  819.                 lp->l_text[lp->l_used++] = (char)c;
  820.             }
  821.             if(*line) 
  822.                       line++;
  823.           }
  824.  
  825.         switch(bind) 
  826.                     {
  827.             case BINDARG:
  828.             bind = BINDDO;
  829.             break;
  830.             case BINDNEXT:
  831.             lp->l_text[lp->l_used] = '\0';
  832.             if((mp = name_mode(lp->l_text)) == NULL) {
  833.                 ewprintf("No such mode: %s", lp->l_text);
  834.                 status = FALSE;
  835.                             FreeLine(lp);
  836.                 goto cleanup;
  837.             }
  838.             curmap = mp->p_map;
  839.                         FreeLine(lp);
  840.             bind = BINDARG;
  841.             break;
  842.             default:
  843.             lp->l_fp = np->l_fp;
  844.             lp->l_bp = np;
  845.             np->l_fp = lp;
  846.             np = lp;
  847.            }
  848.     }
  849.  
  850.     switch(bind) 
  851.           {
  852.         default:
  853.         ewprintf("Bad args to set key");
  854.         status = FALSE;
  855.         break;
  856.         case BINDDO:
  857.             if(fp != unbindtokey && fp != localunbind) 
  858.                   {
  859.             lp->l_text[lp->l_used] = '\0';
  860.             status = bindkey(&curmap, lp->l_text, key.k_chars, 
  861.                 key.k_count);
  862.           } 
  863.                 else 
  864.                   status = bindkey(&curmap, (char *)NULL, key.k_chars, 
  865.                    key.k_count);
  866.         break;
  867.         case BINDNO:
  868.         inmacro = TRUE;
  869.         maclcur = maclcur->l_fp;
  870.         status = (*fp)(f, n);
  871.         inmacro = FALSE;
  872.                 /* fallthru */
  873.       }
  874. cleanup:
  875.     lp = maclcur->l_fp;
  876.     while(lp!=maclcur) 
  877.           {
  878.         np = lp->l_fp;
  879.         free((char *)lp);
  880.         lp = np;
  881.       }
  882.     free((char *)lp);
  883.         maclcur = (LINE *)0;
  884.     return status;
  885. }
  886.  
  887. /*
  888.  * a pair of utility functions for the above
  889.  */
  890. static char *skipwhite(s)
  891. register char *s;
  892. {
  893.     while(ISWHITE(*s) || *s == ')' || *s == '(') 
  894.           s++;
  895.     if (*s == ';') 
  896.           *s = '\0' ;
  897.     return s;
  898. }
  899.  
  900. static char *parsetoken(s)
  901. register char *s;
  902. {
  903.     if (*s != '"') {
  904.         while(*s && !ISWHITE(*s) && *s!=')' && *s!='(') 
  905.               s++;
  906.         if(*s==';') 
  907.               *s='\0';
  908.     } else
  909.         do {    /* Strings get special treatment */
  910.             /* Beware: You can \ out the end of the string! */
  911.         if (*s == '\\') 
  912.                   ++s;
  913.         } while (*++s != '"' && *s != '\0');
  914.     return s;
  915. }
  916.  
  917. void noop()  /* required to provide escape from Window level input loop */
  918. {
  919.   ExtendedFunction(NULL);
  920. }
  921.  
  922. /* Used to push a silent-extended (meta-x like) command into
  923. * input stream.
  924. */
  925. void ExtendedFunction(s)
  926. char *s;
  927. {
  928.   if (macrodef)            /* will cause command line echo */
  929.     {
  930.       if (s && *s)
  931.         {
  932.           AddKchar(METABIT | 'X');    /* user will see this echo */
  933.           AddString(s);
  934.           AddKchar(CCHR('M'));
  935.         }
  936.     }
  937.   else
  938.     {
  939.       AddKchar(KEXTEND);        /* this does not echo */
  940.       if (s && *s)
  941.         AddString(s);
  942.       AddKchar(' ');            /* delimeter for silent_extend! */
  943.     }
  944. }
  945.  
  946. /* read pending input
  947. */
  948. void getcmdinput(buf)
  949. char *buf;
  950. {
  951.   register int i, c;
  952.  
  953.   buf[0] = '\0';
  954.   for (i = 0; (c = (int)getkey(FALSE)) != ' ';) /* ' ' delimiter */
  955.     buf[i++] = (char)c;
  956.   buf[i] = 0;
  957. }
  958.